//@author A0087294-unused
//Due to usage of String^ which has compilation error 
//for integration unit testing. Sorry.

//#include "stdafx.h"
#include "FileIO.h"
#include "FileOutput.h"


LOGGING_DISABLE_LEVEL(::logging::Error);

vector<Event*>* FileIO::eventList = new vector<Event*>;
const std::string FileIO::fileInUse = "TExemplar.txt";
const std::string FileIO::OPERATION_READ = "read";
const std::string FileIO::OPERATION_WRITE = "write";


void FileIO::performReadWrite(string operationType){
	if (operationType == OPERATION_READ){
		readFromFile();
	} else if (operationType == OPERATION_WRITE){
		writeToFile();
	}
	return;
}

std::vector<Event*>* FileIO::getVector(){
	return eventList;
}

FileIO::FileIO(){
	initialiseFile();
	readFromFile();
}

void FileIO::initialiseFile(){
	if (!checkFileExists(getFileName())){
		createNewFile(getFileName());
	}
}

void FileIO::readFromFile(){
	log::emit< Info>()    << "Begin reading operation."   << log::endl;
	
	String^ fileName = gcnew String(fileInUse.c_str());
	FileStream^ fileToRead = gcnew FileStream(fileName, FileMode::Open, FileAccess::ReadWrite);

	StreamReader^ readFromFile = gcnew StreamReader(fileToRead);
	String^ lineFromFile;
	while ( lineFromFile = readFromFile->ReadLine()){
		string convertedLineFromFile = convertToString(lineFromFile);
		analyzeData(convertedLineFromFile);
	}
	fileToRead->Close();

	log::emit< Info>()    << "End reading operation."   << log::endl;
	return;
}

void FileIO::writeToFile(){
	log::emit< Info>()    << "Begin writing operation."   << log::endl;

	vector<string> stringOfEvents;
	for ( unsigned int i = 0; i < eventList->size(); i++ ){
		string eventAndTime = makeIntoString(i);
		stringOfEvents.push_back(eventAndTime);
	}
	addToFile(&stringOfEvents);

	log::emit< Info>()    << "End writing operation."   << log::endl;
}

void FileIO::createNewFile(String^ fileName){
	FileStream^ fs = gcnew FileStream(fileName, FileMode::CreateNew);
	fs->Close();
}

void FileIO::analyzeData(string data){
	std::vector<string> taskDetails;
	parseTaskInfo(data, &taskDetails);
	storeToVector(&taskDetails);
	
	/*
	for (unsigned int i = 0; i < taskDetails.size(); i++){
		std::cout << taskDetails[i];
	}
	std::cout << std::endl;
	for (unsigned int i = 0; i < taskDetails.size(); i++)
	{
		if ( taskDetails[i] == "" ){
			std::cout << i;
		}
	}
	*/
}

void FileIO::storeToVector(std::vector<string>* taskDetails){
	Time* endTime = setEndTime(taskDetails);
	Event* event = new Event((*taskDetails)[0], (*endTime));
	
	Time* startTime = setStartTime(taskDetails);
	event->setStartTime(*startTime);

	eventList->push_back(event);
}

TimeType FileIO::determineTimeType(int index){
	switch (index){
	case 1:
		return TimeType::SECOND;
		break;
	case 2:
		return TimeType::MINUTE;
		break;
	case 3: 
		return TimeType::HOUR;
		break;
	case 4:
		return TimeType::DAY;
		break;
	case 5:
		return TimeType::MONTH;
		break;
	case 6:
		return TimeType::YEAR;
		break;
	}
}

void FileIO::parseTaskInfo (string data, std::vector<string>* taskDetails){
	data = parseTaskDetails(data, taskDetails);
	data = parseTaskStartTime(data, taskDetails);
	parseTaskEndTime(data, taskDetails);
}

string FileIO::parseTaskDetails(string data, std::vector<string>* task){
	std::size_t index = data.find(" | ");
	task->push_back(data.substr(0,index));
	//std::cout << data.substr(0,index);
	data.replace(data.begin(), data.begin()+index+3, "");
	//std::cout << std::endl;
	index = data.find("startTime: ");
	data.replace(data.begin(), data.begin()+index+11, "");
	return data;
}

string FileIO::parseTaskStartTime(string data, std::vector<string>*  task){
	for (unsigned int i = 1; i < 7; i++ ){
		std::size_t index = data.find(" | ");
		task->push_back(data.substr(0,index));
		//std::cout << data.substr(0,index) << std::endl;
		data.replace(data.begin(), data.begin()+index+3, "");
	}
	//std::cout << "6\n" << std::endl;
	std::size_t index = data.find("endTime: ");
	data.replace(data.begin(), data.begin()+index+9, "");
	return data;
}

void FileIO::parseTaskEndTime(string data, std::vector<string>* task){
	for (unsigned int i = 1; i < 7; i++ ){
		std::size_t index = data.find(" | ");
		task->push_back(data.substr(0,index));
		//std::cout << data.substr(0,index) << std::endl;
		data.replace(data.begin(), data.begin()+index+3, "");
	}
}

Time* FileIO::setEndTime(std::vector<string>* taskDetails){
	Time* endTime = new Time;
	
	for (unsigned int i = 7; i < taskDetails->size(); i++){
		TimeType timeType = determineTimeType(i-6);
		bool status = endTime->setTime(timeType, convertToByte((*taskDetails)[i]));
	}
	return endTime;
}

Time* FileIO::setStartTime(std::vector<string>* taskDetails){
	Time* startTime = new Time;

	for (unsigned int i = 1; i < 7; i++){
		TimeType timeType = determineTimeType(i);
		bool status = startTime->setTime(timeType, convertToByte((*taskDetails)[i]));
	}
	return startTime;
}

string FileIO::makeIntoString(int index){

	log::emit< Info>()    << "Getting task details."   << log::endl;
	string eventAndTime = (*eventList)[index]->getDetails() + " | startTime: ";
	
	log::emit< Info>()    << "Getting start time."   << log::endl;
	eventAndTime = storeTime(index, eventAndTime);

	log::emit< Info>()    << "Getting end time."   << log::endl;
	eventAndTime += "endTime: ";
	eventAndTime = storeTime(index, eventAndTime) + "\n";
	
	return eventAndTime;
}

string FileIO::storeTime(int index, string eventAndTime){
	for (int j = 1; j < 7; j++ ){
		CommonDataType::Byte byteTime = (*eventList)[index]->getStartTime().getTime(determineTimeType(j));
		eventAndTime += convertToString(byteTime) + " | ";
	}
	return eventAndTime;
}
 
void FileIO::addToFile(vector<string>* stringOfEvents){
	addContentToFile(stringOfEvents);
}

void  FileIO::addContentToFile(vector<string>* stringOfEvents){
	//string temp = "temp.txt";
	//String^ tempFileName = gcnew String(temp.c_str());
	FileStream^ fileToBeWritten = gcnew FileStream(getFileName(), FileMode::Append, FileAccess::Write);
	StreamWriter^ writeInFile = gcnew StreamWriter(fileToBeWritten);

	for (unsigned int i = 0; i < stringOfEvents->size(); i++){
		String^ contentToBeWritten = gcnew String((*stringOfEvents)[i].c_str());	
		writeInFile->WriteLine(contentToBeWritten);
		writeInFile->Flush();
		fileToBeWritten->Flush();
	}

	fileToBeWritten->Close();

	return;
}

String^ FileIO::getFileName(){
	String^ fileName = gcnew String(fileInUse.c_str());
	return fileName;
}

// This method converts integers to std::string.
string FileIO::convertToString(int index){           
	std::ostringstream convert;   
	convert << index;     
	return convert.str();
}

// This method converts system string to std::string.
string FileIO::convertToString(String^ toBeConverted){
	string convertedToString = marshal_as<std::string>(toBeConverted);
	return convertedToString;
}

// This method converts unsigned char ('Byte') to std::string
string FileIO::convertToString(CommonDataType::Byte byteVariable){
		int timeVariable = byteVariable;
		//std::stringstream ss;
		//ss << byteVariable;
		//return ss.str();
		std::stringstream ss;
		ss << timeVariable;
		return ss.str();
}

CommonDataType::Byte FileIO::convertToByte(string toBeConverted){
	return (CommonDataType::Byte)atoi(toBeConverted.c_str());
}

bool FileIO::checkFileExists(String^ fileName){
	return File::Exists(fileName);
}

string FileIO::getLine(int index){
	return (*eventList)[index]->getDetails();
}


int main(){
	string nouse;
	FileIO fileIO;

	fileIO.performReadWrite("write");

	std::cin >> nouse;

	return 0;
}
